/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { OhosModuleContext } from '@ohos/hvigor-ohos-plugin/src/plugin/context/plugin-context';
import { Logger, ObjectUtils } from '../../framework';
import { FilePathConstants, PrefixConstants, RouterMapConstants } from '../constants';
import { RouterInfo } from '../model';
import { HMRouterExtensionContext } from '../HMRouterExtensionContext';

export class ConfigUpdateProcessor {
  private moduleContext: OhosModuleContext;
  private readonly routerMap: Array<RouterInfo>;
  private readonly nodeName: string;
  constructor(context: HMRouterExtensionContext) {
    this.moduleContext = context.moduleContext;
    this.routerMap = context.routerMap;
    this.nodeName = context.node.getNodeName();
  }

  execute(): void {
    Logger.debug(this.nodeName, `Start to update module.json and build profile...`);
    this.updateModuleJson();
    this.updateBuildProfile();
  }

  /**
   * Update the Module.json configuration
   * @private
   */
  private updateModuleJson(): void {
    // Get the JSON configuration of the module
    const moduleJsonOpt = this.moduleContext.getModuleJsonOpt();
    // Set the name of the routerMap to MODULE_ROUTER_MAP_NAME
    moduleJsonOpt.module.routerMap = RouterMapConstants.MODULE_ROUTER_MAP_NAME;
    // Set the modified moduleJsonOpt to the moduleContext
    this.moduleContext.setModuleJsonOpt(moduleJsonOpt);
    Logger.info(
      this.nodeName,
      `Update module.json5 routerMap successfully, current routerMap: ${
      this.moduleContext.getModuleJsonOpt().module.routerMap
      }`
    );
  }

  /**
   * Update the build configuration
   * @private
   */
  private updateBuildProfile() {
    // Get the build configuration options
    const buildProfileOpt = this.moduleContext.getBuildProfileOpt();
    // Initialize the arkOptions and runtimeOnly configurations
    let sources = ObjectUtils.ensureNestedObject(buildProfileOpt, [
      'buildOption',
      'arkOptions',
      'runtimeOnly',
      'sources',
    ]);
    if (!Array.isArray(sources)) {
      buildProfileOpt.buildOption!.arkOptions!.runtimeOnly!.sources = [];
    }

    // Push the route information to the build configuration options
    this.pushRouterInfo(buildProfileOpt, this.routerMap);

    // Set the build configuration options to the moduleContext
    this.moduleContext.setBuildProfileOpt(buildProfileOpt);
    Logger.info(
      this.nodeName,
      `Update build profile successfully, current sources: ${
      this.moduleContext.getBuildProfileOpt()?.buildOption?.arkOptions?.runtimeOnly?.sources
      }`
    );
  }

  /**
   * @description Add the route information to buildProfileOpt
   * @param buildProfileOpt build configuration options
   * @param routerMap route information
   */
  private pushRouterInfo(buildProfileOpt: any, routerMap: Array<RouterInfo>) {
    let sources = buildProfileOpt.buildOption.arkOptions.runtimeOnly.sources;

    routerMap.forEach((item: RouterInfo) => {
      const name = item.name;
      if (
        name.includes(PrefixConstants.LIFECYCLE_PREFIX) ||
        name.includes(PrefixConstants.INTERCEPTOR_PREFIX) ||
        name.includes(PrefixConstants.ANIMATOR_PREFIX) ||
        name.includes(PrefixConstants.SERVICE_PREFIX) ||
        name.includes(PrefixConstants.SERVICE_PROVIDE_PREFIX)
      ) {
        sources.push(FilePathConstants.CURRENT_DELIMITER + item.pageSourceFile);
      }
    });

    sources = [...new Set(sources)];
  }
}
